/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package dcm4che;

import GUI.JFrameBase;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import libraries.PathLibrary;
import libraries.SystemCall;
import model.DB2Hash;
import org.dcm4che2.data.DicomElement;
import org.dcm4che2.data.DicomObject;
import org.dcm4che2.tool.dcmmwl.DcmMWL;

/*CP="$CP:$DCM4CHE_HOME/lib/dcm4che-core-2.0.24.jar"
CP="$CP:$DCM4CHE_HOME/lib/dcm4che-net-2.0.24.jar"
CP="$CP:$DCM4CHE_HOME/lib/slf4j-log4j12-1.6.1.jar"
CP="$CP:$DCM4CHE_HOME/lib/slf4j-api-1.6.1.jar"
CP="$CP:$DCM4CHE_HOME/lib/log4j-1.2.16.jar"
CP="$CP:$DCM4CHE_HOME/lib/commons-cli-1.2.jar"*/

/**
 *
 * @author aeguzkiza
 */
public class dcmMWL {
    public static class MyException extends Exception { // TESTING THIS POSSIBILITY.
        static final int FileError = 1;
        static final int SystemCallError = 2;
        static final int ServerError = 3;
        private int type;
        private String string;
        
        public MyException(int type, String string) {
            super();
            this.type = type;
            this.string = string;
        }

        @Override
        public String getMessage() {
            switch (type) {
            case FileError:
                    return "No se ha encontrado el archivo correspondiente a la adquisición seleccionada en la ruta:\n["+string+" ]";
            case SystemCallError:
                    return "Es posible que la configuración del servidor no sea correcta, \npara resolver el problema revise la ventana de configuración.\n\nHa surgido un fallo de comunicación con el PACS al realizar la siguiente llamada cmd:\n["+string+" ]";
            case ServerError:
                    return "ERROR: Fallo al intentar establecer asociación con el servidor ["+string+"]"; 
            default:
                    return "Error desconocido: string = "+string+" type = "+type;
            }
        }
    }
    
    // Loading libraries
    //MySQL_Query DB = new MySQL_Query();
    SystemCall SC = new SystemCall();
    PathLibrary PL = new PathLibrary();
    //DcmMWL dcmmwl = new DcmMWL("dcmmwl -mod=OPV -date=20110628");
    //DcmMWL dcmmwl = new DcmMWL("dcmmwl");
    //DcmGPWL dcmgpwl = new DcmGPWL("dcmgpwl");

    // Global variables 
    private String pathLibrary = PL.getdcm4chePath();   // Get's the path where library is located.; 
    
    private String options = "";
    
    private String dcm4che = null;
    private String cmd = null;
    private String buffer = null;
    private boolean isError = false;
    private String error = "";
    private List<DicomObject> worklist;
    
    private String ScheduledProcedureStepID;
    private String worklistId = "400009";   // Tag of the worklist identifier attribute.
    
    public dcmMWL(JFrameBase frame, DB2Hash device, DB2Hash server, ArrayList<String> filters) throws MyException, SQLException, IOException, InterruptedException, Exception {     // Follows all the sending process.
        
        System.out.println("pathLibrary: "+this.pathLibrary);        
        //DcmMWL dcmmwl = new DcmMWL("dcmmwl "+server.get("AETitle")+"@"+server.get("HostIP")+":"+server.get("HostPort")+" "+options);
                
        /* WORKS!!! THROUGH CMD
        //options = "-mod=OPV -aet=AITOR -date="+frame.parseDate(null);   // Requests the worklist by the AETitle of the device, by the modality selected,and today's date. .
        options = "-mod="+device.get("Modality")+" -aet="+device.get("AETitle");   // Requests the worklist by the AETitle of the device, by the modality selected,and today's date. .
        System.out.println("dcmMWL options: "+options);

        // DCM4CHE2 VIA COMMAND LINE:
        String pathDcmmwl = pathLibrary+"\\dcmmwl";
        this.dcm4che = "\""+pathDcmmwl+"\" "+server.get("AETitle")+"@"+server.get("HostIP")+":"+server.get("HostPort")+" "+options;
        this.cmd = "cd \""+pathLibrary+"\" && "+dcm4che+"\n";*/
                
        
        DcmMWL dcmmwl = new DcmMWL("dcmmwl");
        this.buffer = null;

        // Code created from public functions from DcmMWL.
        dcmmwl.setCalledAET(server.get("AETitle"));
        dcmmwl.setRemoteHost(server.get("HostIP"));
        dcmmwl.setRemotePort(Integer.parseInt(server.get("HostPort")));
                
        // Filter worklist query:    
        
        // Query parameters from config:
        //dcmmwl.addSpsMatchingKey(0x00400001, device.get("AETitle"));    // Only studies associated to this device.
        dcmmwl.addSpsMatchingKey(0x00080060, device.get("Modality"));   // Only modalities associated to this device.
        
        // Query parameters from user:        
        System.out.println("Filters: "+filters);
                
        int Tag[] = new int[1];
        for(int i=0;i<filters.size()/2;i++){                       
            String Value = filters.get(2*i+1);
            if(i == 0){
                Value = Value.replaceAll("/", "");
                int Tag0 = Integer.parseInt(filters.get(2*i),16);
                System.out.println("Filter"+i+" > Tag (Integer): "+Integer.toHexString(Tag0)+" Value: "+Value);
                dcmmwl.addSpsMatchingKey(Tag0, Value); 
            }else{
                Tag[0] = Integer.parseInt(filters.get(2*i), 16);  // Hexadecimal to int.            
                System.out.println("Filter"+i+" > Tag (Integer): "+Integer.toHexString(Tag[0])+" Value: "+Value);
                dcmmwl.addMatchingKey(Tag, Value);    
            }
        }    
                        
        //dcmmwl.setPackPDV(!cl.hasOption("pdv1"));
        dcmmwl.setPackPDV(true);
        //dcmmwl.setTcpNoDelay(!cl.hasOption("tcpdelay"));
        dcmmwl.setTcpNoDelay(true);

        //dcmmwl.setTransferSyntax(cl.hasOption("ivrle") ? IVRLE_TS : LE_TS);
        String[] IVRLE_TS = { "1.2.840.10008.1.2" };
        String[] LE_TS = { "1.2.840.10008.1.2.1", "1.2.840.10008.1.2" };
        dcmmwl.setTransferSyntax(LE_TS);

        long t1 = System.currentTimeMillis();    
        dcmmwl.open();
         
        long t2 = System.currentTimeMillis();
        System.out.println("Connected to " + server.get("AETitle") + " in " + (float)(t2 - t1) / 1000.0F + "s");
        
        // Filter before the query:
        //dcmmwl.addSpsMatchingKey(0x00100010, "AITOR");
        
        // Query the Worklist to the PACS:
        List result = dcmmwl.query();   // Returns a list of DICOM objects.
        
        long t3 = System.currentTimeMillis();
        System.out.println("Received " + result.size() + " matching entries in " + (float)(t3 - t2) / 1000.0F + "s");
        
        // Put error 0 study matched.
        
        this.worklist = result;          
        dcmmwl.close();
                
        System.out.println("Released connection to " + server.get("AETitle"));


        /* WORKS!!! THROUGH CMD
        Object result[] = SC.SystemCall(cmd);
        this.isError = Boolean.valueOf(result[0].toString());         // Cast Object to boolean.
        this.error = "Error en los parámetros de configuración de captura de la Worklist";
        this.buffer = (String) result[1];
        System.out.println("ERROR RESULT: "+error);*/
        
        
        
        // Update worklist and Study tables using captured information.
        /*String[] var0 = new String[]{"1"};  // Write send=1 on database for the corresponding acquisition.
        DB.SQLupdate("UPDATE acquisition SET Sent=? WHERE AcquisitionName='"+acquisition+"'",false,var0.length,var0);
        DB.closeConnection();*/
    
    }
    public List<DicomObject> getWorklist(){ // Array co0ntaining scheduled study list.
        return this.worklist;
    }
    public String getDcm4che(){
        return this.dcm4che;
    }
    public String getCMD(){
        return this.cmd;
    }
    public String getBuffer(){
        return this.buffer;
    }
    public String getError(){
        return this.error;
    }
    public ArrayList<ArrayList<String>> Dicom2Array(DicomObject object) throws IOException{
        // Creates a list of attributes. Including even those from sub sequences.

        ArrayList<ArrayList<String>> worklist = new ArrayList();
        ArrayList<String> tagList = new ArrayList();
        ArrayList<String> nameList = new ArrayList();
        ArrayList<String> vrList = new ArrayList();
        ArrayList<String> vmList = new ArrayList();
        ArrayList<String> vlList = new ArrayList();
        ArrayList<String> valueList = new ArrayList();
        Iterator<DicomElement> iter = object.iterator();    // Next attribute.
        
        
        
        while(iter.hasNext() ){
            ArrayList<String> attributes = new ArrayList();
            DicomElement element = iter.next();//next elementData            
            String tagName = null;
            String tagVM = null;
            String tagVL = null;
            String value = null;
            
            int tag = element.tag();
            String tagVR = ((DicomObject) object).vrOf(tag).toString();           
                        
            /*Read tag items*/
            if (tagVR.equals("SQ")|element.hasDicomObjects()){
                if(element.hasItems() && element.getDicomObject() != null){     //if item in metadata
                    // start of sub-sequence.
                    element.addDicomObject(element.getDicomObject());
                    tag = element.tag();  
                    tagName = ((DicomObject) object).nameOf(tag);        
                    tagVR = ((DicomObject) object).vrOf(tag).toString();
                    tagVM = Integer.toString(((DicomObject) object).vm(tag));
                    tagVL = Integer.toString(((DicomObject) object).size());                    
                                        
                    // Get sub-sequence attributes.
                    DicomElement subElement = object.get(tag);
                    DicomObject s1 =null;

                    if (subElement.hasDicomObjects() ){
                        for(int i=1;i<subElement.countItems();i++)
                            s1 = subElement.getDicomObject(i);

                            // Add SQ attribute to the ArrayList.
                            /*Nx3 Matrix.
                            attributes.add(Integer.toHexString(tag));
                            attributes.add(tagVR);
                            attributes.add(value);
                            worklist.add(attributes);*/
                            tagList.add(Integer.toHexString(tag));
                            nameList.add(((DicomObject) object).nameOf(tag));
                            vrList.add(tagVR);
                            vmList.add(tagVM);
                            vlList.add(tagVL);
                            valueList.add("SQ");    // Assign a value to each filled SQ.
                            //System.out.println("Tag: "+Integer.toHexString(tag)+" TagVR: "+tagVR+" Value: "+value);

                            // Add attributes from sub-sequences to ArrayList.
                            //System.out.println(" > Start of Sub-Element:");
                            // 3xN Matrix.
                            ArrayList<ArrayList<String>> subAttributes = Dicom2Array(s1);    // Extract data from sub-element.
                            //worklist.addAll(subAttributes);
                            tagList.addAll(subAttributes.get(0));
                            nameList.addAll(subAttributes.get(1));
                            vrList.addAll(subAttributes.get(2));
                            vmList.addAll(subAttributes.get(3));
                            vlList.addAll(subAttributes.get(4));
                            valueList.addAll(subAttributes.get(5));  
                            //System.out.println(" > End of Sub-Element:");
                            
                    }
                    continue;
                }
            }
                        
            // Add rest of attributes to ArrayList.
            tagName = ((DicomObject) object).nameOf(tag);              
            tagVM = Integer.toString(((DicomObject) object).vm(tag));
            //tagVL = Integer.toString(((DicomObject) object).size());
            tagVL = Integer.toString(((DicomObject) object).getString(tag,tagVR).length());
            value = object.getString(tag,tagVR);
            
            if(Integer.toHexString(tag).equals(this.worklistId)){  // Saves the attribute which identifies the referral note into the PACS.
                this.ScheduledProcedureStepID = value;
            }
            //System.out.println("tag: "+Integer.toHexString(tag)+"\t>tagVR: "+tagVR+"\t>tagVM: "+tagVM+"\t>tagVL: "+tagVL+"\t>tagName: "+tagName+"\tvalue: "+value);
            
            //System.out.println("("+Integer.toHexString(tag)+") "+tagVR+" {"+tagVM+"} #"+tagVL+" "+tagName+" ["+value+"]");
            //if(value.equals(tagVR)){value="";}    // Avoids fake assignements.
            
            /*attributes.add(Integer.toHexString(tag));
            attributes.add(tagVR);
            attributes.add(value);
            
            worklist.add(attributes);
            System.out.println("Tag: "+Integer.toHexString(tag)+" TagVR: "+tagVR+" Value: "+value);*/
            if(!tagVM.equals("0") && !value.equals(tagVR) && !value.isEmpty() && value.length() != 0){ // Deletes fake or empty attributes.
                tagList.add(Integer.toHexString(tag));
                nameList.add(tagName);
                vrList.add(tagVR);
                vmList.add(tagVM);
                vlList.add(tagVL);
                valueList.add(value);     
                //System.out.println("("+Integer.toHexString(tag)+") "+tagVR+" {"+tagVM+"} #"+tagVL+" "+tagName+" ["+value+"]");                                     
            }                            
        }
        worklist.add(tagList);
        worklist.add(nameList);
        worklist.add(vrList);
        worklist.add(vmList);
        worklist.add(vlList);
        worklist.add(valueList);
        return worklist;
    }
    
        
    public String getScheduledProcedureStepID(){
        return this.ScheduledProcedureStepID;
    }
}
